package com.qd.system.importexcel.personrole;

import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.cdqidi.dto.BatchResult;
import com.cdqidi.excel.domain.ExcelRowMsg;
import com.cdqidi.excel.domain.ImportErr;
import com.cdqidi.excel.util.ExcelUtil;
import com.cdqidi.exception.ExcelOperatorException;
import com.cdqidi.util.ValidatorUtil;
import com.cdqidi.valid.group.DefaultGroup;
import com.qd.common.sys.domain.entity.person.PersonRoleDTO;
import com.qd.system.model.PersonRole;
import com.qd.system.service.dict.MbUtil;
import com.qd.system.service.person.PersonRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.util.stream.Collectors.toList;

/**
 * 用户和角色,excel导入处理类
 *
 * @author sjk
 */
@Slf4j
public class PersonRoleImportHandler {

    private final PersonRoleService personRoleService;
    private final ValidatorUtil validatorUtil;
    private final List<ImportErr> errorList;
    private final LocalDateTime now = LocalDateTime.now();

    public PersonRoleImportHandler(PersonRoleService personRoleService, ValidatorUtil validatorUtil, List<ImportErr> errorList) {
        this.personRoleService = personRoleService;
        this.validatorUtil = validatorUtil;
        this.errorList = errorList;
    }

    /**
     * 处理具体导入
     *
     * @param rowList excel行数据集合，默认为1000行
     * @param results 异常信息存储
     */
    public void process(List<ExcelRowMsg<PersonRoleDTO>> rowList, List<BatchResult> results) {
        final List<PersonRoleDTO> personRoleList = rowList.stream().map(ExcelRowMsg::getRowData).collect(toList());
        final List<String> personIds = personRoleList.stream().map(PersonRoleDTO::getPersonId).filter(StringUtils::hasLength).collect(toList());
        final List<String> roleIds = personRoleList.stream().map(PersonRoleDTO::getRoleId).filter(StringUtils::hasLength).collect(toList());
        final List<String> existsPersonIds = personRoleService.getPersonService().getBaseMapper().getIds(personIds);
        final List<String> existsRoleIds = personRoleService.getRoleService().getBaseMapper().getIds(roleIds);
        final List<String> existsPersonRoles = existsPersonRoles(existsPersonIds, existsRoleIds);

        final List<String> existsIds = existsIds(personRoleList);
        final int size = rowList.size();
        try {
            for (ExcelRowMsg<PersonRoleDTO> excelRowMsg : rowList) {
                final List<String> errors = new ArrayList<>();
                final PersonRoleDTO PersonRoleDTO = excelRowMsg.getRowData();
                final ReadRowHolder readRowHolder = excelRowMsg.getReadRowHolder();
                importValidate(PersonRoleDTO, errors);
                importBaseColumn(PersonRoleDTO, existsPersonIds, existsRoleIds, existsPersonRoles, errors);
                if (!errors.isEmpty()) {
                    errorList.add(ExcelUtil.buildError(readRowHolder, errors));
                }
            }
            if (!errorList.isEmpty()) {
                throw new ExcelOperatorException(errorList);
            } else {
                final List<PersonRole> addPersonRoleList = new ArrayList<>(size);
                final List<PersonRole> updatePersonRoleList = new ArrayList<>(size);
                doProcessDictData(existsIds, personRoleList, addPersonRoleList, updatePersonRoleList);
                BatchResult.buildBatchResult(results, addPersonRoleList.size(), updatePersonRoleList.size());
                addPersonRoleList.clear();
                updatePersonRoleList.clear();
            }
        } finally {
            personRoleList.clear();
            existsIds.clear();
        }
    }

    /**
     * @param PersonRoleDTO     excel行数据
     * @param existsPersonIds   已经存在的人员ID集合
     * @param existsRoleIds     已经存在的角色ID集合
     * @param existsPersonRoles 已经存在的人员和角色关系（存储的人员ID）
     * @param errors            异常信息
     */
    private void importBaseColumn(PersonRoleDTO PersonRoleDTO, List<String> existsPersonIds, List<String> existsRoleIds, List<String> existsPersonRoles, List<String> errors) {
        boolean isNotCheck = false;
        if (!MbUtil.isExistInCollection(existsPersonIds, PersonRoleDTO.getPersonId())) {
            errors.add("人员ID不存在[" + PersonRoleDTO.getPersonId() + "]");
            isNotCheck = true;
        }
        if (!MbUtil.isExistInCollection(existsRoleIds, PersonRoleDTO.getRoleId())) {
            errors.add("角色ID不存在[" + PersonRoleDTO.getRoleId() + "]");
            isNotCheck = true;
        }
        if (isNotCheck) {
            return;
        }
        if (MbUtil.isExistInCollection(existsPersonRoles, PersonRoleDTO.getPersonId())) {
            errors.add("人员和角色关系已经分配[" + PersonRoleDTO.getPersonId() + "|" + PersonRoleDTO.getRoleId() + "]");
        }
    }

    /**
     * 查询人员和角色关系
     *
     * @param existsPersonIds 人员ID集合
     * @param existsRoleIds   角色ID集合
     * @return 存在的人员ID
     */
    private List<String> existsPersonRoles(List<String> existsPersonIds, List<String> existsRoleIds) {
        if (existsPersonIds.isEmpty() || existsRoleIds.isEmpty()) {
            return Collections.emptyList();
        }
        return personRoleService.getBaseMapper().getPersonRoles(existsPersonIds, existsRoleIds);
    }

    /**
     * 保存数据
     *
     * @param existsIds            已经存在的数据库主键
     * @param personRoleList       excel行数据集合
     * @param addPersonRoleList    添加集合
     * @param updatePersonRoleList 更新集合
     */
    private void doProcessDictData(List<String> existsIds, List<PersonRoleDTO> personRoleList, List<PersonRole> addPersonRoleList, List<PersonRole> updatePersonRoleList) {
        personRoleList.forEach(PersonRoleDTO -> {
            final PersonRole personRole = personRoleService.dtoToModel(PersonRoleDTO);
            personRoleService.clearCache(personRole);
            if (MbUtil.isExistInCollection(existsIds, PersonRoleDTO.getPersonRoleId())) {
                personRole.setAddTime(null);
                personRole.setUpdateTime(now);
                updatePersonRoleList.add(personRole);
            } else {
                personRole.setAddTime(now);
                personRole.setUpdateTime(null);
                addPersonRoleList.add(personRole);
            }
        });
        if (!addPersonRoleList.isEmpty()) {
            personRoleService.saveBatch(addPersonRoleList);
        }
        if (!updatePersonRoleList.isEmpty()) {
            personRoleService.updateBatchById(updatePersonRoleList);
        }
    }

    /**
     * 获得主键存在的集合
     *
     * @param personRoleList excel行数据集合
     * @return 主键集合
     */
    private List<String> existsIds(List<PersonRoleDTO> personRoleList) {
        final List<String> ids = personRoleList.stream().map(PersonRoleDTO::getPersonRoleId).collect(toList());
        final List<String> existsIds = personRoleService.getBaseMapper().getIds(ids);
        ids.clear();
        return existsIds;
    }

    /**
     * 导入实体验证
     *
     * @param PersonRoleDTO 单个excel行数据
     * @param errors        异常信息存储
     */
    private void importValidate(PersonRoleDTO PersonRoleDTO, List<String> errors) {
        if (errors.isEmpty()) {
            try {
                validatorUtil.checkValid(PersonRoleDTO, DefaultGroup.class);
            } catch (ConstraintViolationException e) {
                errors.addAll(validatorUtil.getValidationError(e));
            }
        }
    }
}